home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Programming Contest / ~Solutions Submitted / Problem 04 - Jager & Quinn / Solution.cp < prev   
Encoding:
Text File  |  1998-06-19  |  7.9 KB  |  329 lines  |  [TEXT/CWIE]

  1. /*
  2. Problem 04 - Text Processing
  3.  
  4. const
  5.     kMaxHandleSize = 1000000;
  6. const
  7.     kActionMove = 1;
  8.     kActionInsert = 2;
  9.     kActionDelete = 3;
  10.     kActionSearch = 4;
  11.     kActionSearchAndReplace = 5;
  12. const
  13.     kFlagCaseSensitiveBit = 0;
  14.     kFlagGlobalBit = 1;
  15.     kFlagBackwardsBit = 2;
  16. type
  17.   ActionRecord = record
  18.     action: UInt32;
  19.     amount: SInt32;
  20.     flags: UInt32;
  21.     search: Str255;
  22.     replace: Str255;
  23.   end;
  24.   ActionRecordArray = array[0..0] of ActionRecord;
  25.   ActionRecordArrayPtr = ^ActionRecordArray;
  26.  
  27. procedure TextProcess( data: Handle; action_count: UInt32; actions:
  28. ActionRecordArrayPtr );
  29.  
  30. Given an unlocked handle to a block of text, you need to apply a sequence of
  31. actions to the data.  You will be required to insert text, delete text, search
  32. for text, search for and replace text.  All required actions take place at the
  33. position of the current selection pointer, which starts at zero, before the
  34. first character in the data.  In response to each of the action commands you
  35. need to perform the following:
  36.  
  37. kActionMove - move the internal position forward by the amount field (which may
  38. be negative).  (Example, kActionMove with amount set to kMaxHandleSize will set
  39. the internal pointer to be GetHandleSize( data )).
  40.  
  41. kActionInsert - Insert the replace string at the current location.  (Example,
  42. if the internal pointer is GetHandleSize( data ), then the replace string will
  43. be appended to the handle.
  44.  
  45. kActionDelete - Delete the number of characters specified by the amount field. 
  46. The internal position pointer is never moved.  If the amount field is greater
  47. than the number of characters after the internal pointer, then fewer characters
  48. are deleted such that the handle is truncated at the current value of the
  49. selection pointer.
  50.  
  51. kActionSearch - search forward (backwards if the kFlagBackwardsBit is set in
  52. the flags field) for the search field (case sensitively if the
  53. kFlagCaseSenstitiveBit is set in the flags field).  The position pointer should
  54. be set to point before the first character of the string if it is found, or at
  55. GetHandleSize (zero if backwards) if not found.  If there is a match at the
  56. initial position, it is not counted (ie, kActionMove -kMaxHandleSize, kSearch
  57. 'hello', kSearch 'hello' finds the second occurance of 'hello').
  58.  
  59. kActionSearchAndReplace - search forward (or backward if the kFlagBackwardsBit
  60. is set in the flags field), but when a match is found, replace it with the
  61. replace string, leaving the position pointer unmoved.  If the kFlagGlobalBit is
  62. set in the flags field, continue searching as long matches continues to be
  63. found.  Repeated searches begin after the previous replace string (i.e., never
  64. replace any characters of the replace string).  For example, if you replace
  65. 'aaa' with 'ABA' (case insensitively) in 'aaaaaaaa' you will get 'ABAABAaa',
  66. not 'ABABABAa'.  Replace never moves the internal position pointer.
  67.  
  68. The internal selection pointer is constrained to be in the range of 0 and
  69. GetHandleSize(data), inclusive, at all times.  Should any action cause the
  70. selection pointer to become less than zero (or greater than GetHandleSize),
  71. then you must reset it to zero (or GetHandleSize, respectively).  The handle
  72. size will never exceed 1 Meg, and you will have plenty of memory to play with.  
  73.  
  74. Characters from chr(127)-chr(255) will never appear in the handle or any
  75. strings.  
  76. */
  77.  
  78. #include "Solution.h"
  79. #include <ctype.h>
  80.  
  81. // Fill in your solution and then submit this folder
  82.  
  83. // Team Name: Jager & Quinn
  84.  
  85. enum {
  86.     kFlagCaseSenstitiveMask = 0x0001,
  87.     kFlagGlobalMask = 0x0002,
  88.     kFlagBackwardsMask = 0x0004,
  89. };
  90.  
  91. static void FixCursor(Handle data, long* cursor)
  92. {
  93.     if (*cursor < 0)
  94.     {
  95.         *cursor = 0;
  96.     }
  97.     if (*cursor > GetHandleSize(data) )
  98.     {
  99.         *cursor = GetHandleSize(data);
  100.     }
  101. }
  102.  
  103. static void DoMove(Handle data, long* cursor, SInt32 amt)
  104. {
  105.     *cursor += amt;
  106.     FixCursor(data,cursor);
  107. }
  108.  
  109. static void DoInsert(Handle data, long* cursor, Str255 str)
  110. {
  111.     long strlen = str[0] & 0x00FF;
  112.     long datalen = GetHandleSize(data);
  113.     
  114.     FixCursor(data,cursor);
  115.     if (strlen > 0)
  116.     {
  117.         
  118.         if (*cursor >= datalen)
  119.         {
  120.             PtrAndHand(&str[1],data,strlen);
  121.         }
  122.         else
  123.         {
  124.             SetHandleSize(data, datalen + strlen);
  125.             BlockMoveData(&(*data)[*cursor],&(*data)[*cursor+strlen],datalen - *cursor);
  126.             BlockMoveData(&str[1],&(*data)[*cursor],strlen);
  127.         }
  128.     }
  129.     FixCursor(data,cursor);
  130. }
  131.  
  132. static void DoDelete(Handle data, long* cursor, SInt32 amt)
  133. {
  134.     FixCursor(data,cursor);
  135.     if (amt > 0)
  136.     {
  137.         long datalen = GetHandleSize(data);
  138.         
  139.         if (*cursor + amt >= datalen)
  140.         {
  141.             SetHandleSize(data,*cursor);
  142.         }
  143.         else
  144.         {
  145.             BlockMoveData(&(*data)[*cursor+amt],&(*data)[*cursor],datalen - *cursor - amt);
  146.             SetHandleSize(data,datalen - amt);
  147.         }
  148.     }
  149.     FixCursor(data,cursor);
  150. }
  151.  
  152. static Boolean DoMatch(UInt32 flags,char *s1,char *s2,long len)
  153. {
  154.     if ((flags & kFlagCaseSenstitiveMask) == kFlagCaseSenstitiveMask)
  155.     {
  156.         while (len > 0)
  157.         {
  158.             if (*s1 != *s2)
  159.             {
  160.                 break;
  161.             }
  162.             s1++;
  163.             s2++;
  164.             len--;
  165.         }
  166.     }
  167.     else
  168.     {
  169.         while (len > 0)
  170.         {
  171.             if (toupper(*s1) != toupper(*s2))
  172.             {
  173.                 break;
  174.             }
  175.             s1++;
  176.             s2++;
  177.             len--;
  178.         }
  179.     }
  180.     
  181.     return (len == 0);
  182. }
  183.  
  184. static Boolean DoSearchForwards(Handle data, long* cursor, UInt32 flags, Str255 str)
  185. {
  186.     long strlen = str[0] & 0x00FF;
  187.     long datalen = GetHandleSize(data);
  188.  
  189.     *cursor += 1;
  190.     while (*cursor + strlen <= datalen)
  191.     {
  192.         if (DoMatch(flags,&(*data)[*cursor],(char*) &str[1],strlen) )
  193.         {
  194.             return true;
  195.         }
  196.         *cursor += 1;
  197.     }
  198.     *cursor = datalen;
  199.     return false;
  200. }
  201.  
  202. static Boolean DoSearchBackwards(Handle data, long* cursor, UInt32 flags, Str255 str)
  203. {
  204.     long strlen = str[0] & 0x00FF;
  205.     long datalen = GetHandleSize(data);
  206.  
  207.     *cursor -= 1;
  208.     if (*cursor + strlen > datalen)
  209.     {
  210.         *cursor = datalen - strlen;
  211.     }
  212.     while (*cursor >= 0)
  213.     {
  214.         if (DoMatch(flags,&(*data)[*cursor],(char*) &str[1],strlen) )
  215.         {
  216.             return true;
  217.         }
  218.         *cursor -= 1;
  219.     }
  220.     *cursor = 0;
  221.     return false;
  222. }
  223.  
  224. static Boolean DoSearch(Handle data, long* cursor, UInt32 flags, Str255 str)
  225. {
  226.     if ((flags & kFlagBackwardsMask) == kFlagBackwardsMask)
  227.     {
  228.         return DoSearchBackwards(data,cursor,flags,str);
  229.     }
  230.     else
  231.     {
  232.         return DoSearchForwards(data,cursor,flags,str);
  233.     }
  234. }
  235.  
  236. static Boolean DoOneReplaceForwards(Handle data, long* cursor, UInt32 flags, Str255 str,Str255 rlpc)
  237. {
  238.     if ( DoSearchForwards(data,cursor,flags,str) )
  239.     {
  240.         DoDelete(data,cursor,(str[0] & 0x00FF));
  241.         DoInsert(data,cursor,rlpc);
  242.         *cursor =+ (rlpc[0] & 0x00FF);
  243.         FixCursor(data,cursor);
  244.         return true;
  245.     }
  246.     return false;
  247. }
  248.  
  249. static Boolean DoOneReplaceBackwards(Handle data, long* cursor, UInt32 flags, Str255 str,Str255 rlpc)
  250. {
  251.     if ( DoSearchBackwards(data,cursor,flags,str) )
  252.     {
  253.         DoDelete(data,cursor,(str[0] & 0x00FF));
  254.         DoInsert(data,cursor,rlpc);
  255.         *cursor =- (str[0] & 0x00FF);
  256.         FixCursor(data,cursor);
  257.         return true;
  258.     }
  259.     return false;
  260. }
  261.  
  262. static Boolean DoOneReplace(Handle data, long* cursor, UInt32 flags, Str255 str,Str255 rlpc)
  263. {
  264.     if ((flags & kFlagBackwardsMask) == kFlagBackwardsMask)
  265.     {
  266.         return DoOneReplaceBackwards(data,cursor,flags,str,rlpc);
  267.     }
  268.     else
  269.     {
  270.         return DoOneReplaceForwards(data,cursor,flags,str,rlpc);
  271.     }
  272. }
  273.  
  274. static void DoReplace(Handle data, long* cursor, UInt32 flags, Str255 str,Str255 rlpc)
  275. {
  276.     FixCursor(data,cursor);
  277.     
  278.     long cur = *cursor;
  279.  
  280.     if ( (flags & kFlagGlobalMask) == kFlagGlobalMask)
  281.     {
  282.         while (DoOneReplace(data,&cur,flags,str,rlpc)) {};
  283.     }
  284.     else
  285.     {
  286.         DoOneReplace(data,&cur,flags,str,rlpc);
  287.     }
  288.     FixCursor(data,cursor);
  289. }
  290.  
  291. pascal void TextProcess( Handle data, UInt32 action_count, ActionRecord *actions )
  292. {
  293.     long idx = 0;
  294.     long cursor = 0;
  295.     
  296.     if ( (data == 0) || (actions == 0) )
  297.     {
  298.         return;
  299.     }
  300.     
  301.     while (idx < action_count)
  302.     {
  303.         switch (actions[idx].action) {
  304.             case kActionMove :
  305.                 DoMove(data,&cursor,actions[idx].amount);
  306.                 break;
  307.                 
  308.             case kActionInsert :
  309.                 DoInsert(data,&cursor,actions[idx].search);
  310.                 break;
  311.                 
  312.             case kActionDelete :
  313.                 DoDelete(data,&cursor,actions[idx].amount);
  314.                 break;
  315.                 
  316.             case kActionSearch :
  317.                 DoSearch(data,&cursor,actions[idx].flags,actions[idx].search);
  318.                 break;
  319.                 
  320.             case kActionSearchAndReplace :
  321.                 DoReplace(data,&cursor,actions[idx].flags,actions[idx].search,actions[idx].replace);
  322.                 break;
  323.  
  324.         }
  325.         idx++;
  326.     }
  327.  
  328.     return;
  329. }